/*
	Copyright (C) 2010 2011 Rémi Thebault

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <QGraphicsItem>
#include <QGraphicsScene>
#include <QPainter>
#include <QPainterPath>

#include <procycle/cycle.h>

#include "ganttmtask.h"
#include "ganttatask.h"
#include "ganttscene.h"
#include "timeaxis.h"
#include "procycle.h"
#include "taskviewhelper.h"


GanttMTask::GanttMTask(ProCycle* app, PC::MacroTask* task, GanttCycle* gcycle, GanttMTask* parent) :
	GanttTask(app, task, gcycle, parent)
{
	for (PC::Task::const_iterator ti=task->taskBegin();
			ti!=task->taskEnd();
			++ti) {
		GanttTask* gt = GanttScene::createGTask(app, *ti, gcycle, this);
		addTask(gt);
	}
	replaceChildren();
}




QRectF GanttMTask::boundingRect() const {
	TaskViewHelper tvh (m_task);
	return QRectF(
			0,
			0,
			scene()->width(),
			app()->rowHeight()*tvh.visualHeight()
	);
}


void GanttMTask::paintTaskBar(QPainter *painter) {
	painter->save();

	bool cp = m_drawCriticalPath && m_task->isCriticalPath();

	TaskViewHelper tvh (m_task);
	if (tvh.isExpanded()) {
		QRect backR = m_rect;
		backR.translate(0, barHeight());
		int bh = tvh.visualHeight()*app()->rowHeight();
		bh -= (barHeight()+barTop());
		backR.setHeight(bh);
		backR.setWidth(backR.width()+1);

		QColor backC (0, 0, 128, 32);
		painter->fillRect(backR, backC);
	}

	int arrowW = 8;
	QRect arrowL = m_rect;
	arrowL.setWidth(arrowW);
	arrowL.translate(-arrowW/2, 0);
	QRect arrowR = arrowL;
	arrowR.translate(m_rect.width(), 0);

	QPainterPath path(arrowL.topLeft());
	path.lineTo(arrowL.bottomLeft());
	path.lineTo(m_rect.left(), barBottom());
	path.lineTo(arrowL.bottomRight());
	path.lineTo(arrowR.bottomLeft());
	path.lineTo(m_rect.right(), barBottom());
	path.lineTo(arrowR.bottomRight());
	path.lineTo(arrowR.topRight());
	path.closeSubpath();

	QColor c = GanttScene::colorForTask(m_task);
	painter->setBrush(cp ? QColor(0xed, 0xbb, 0xc8) : c);

	QPen pen (cp ? QColor(Qt::red) : GanttScene::borderColor(c));
	pen.setWidth((hovered()||isSelected()) ? 2 : 1);
	painter->setPen(pen);

	painter->drawPath(path);

	painter->restore();
}



bool GanttMTask::pointOnTaskBar(const QPointF &p) {
	return (p.x() <= m_rect.right() && p.x() >= m_rect.left() &&
			(p.y() >= m_rect.top() && p.y() <= m_rect.bottom()));
}


void GanttMTask::addTask(GanttTask* gt) {
	if (gt->parentItem() != this) {
		gt->setParentItem(this);
	}
	m_gtasks.append(gt);
}

void GanttMTask::insertTask(GanttTask* gt, int pos) {
	if (gt->parentItem() != this) {
		gt->setParentItem(this);
	}
	m_gtasks.insert(pos, gt);
}

void GanttMTask::removeTask(GanttTask* gt) {
	m_gtasks.removeAll(gt);
}

void GanttMTask::removeAllTasks() {
	foreach(GanttTask* gt, m_gtasks) {
		if (GanttMTask* gmt = dynamic_cast<GanttMTask*>(gt)) {
			gmt->removeAllTasks();
		}
		scene()->removeItem(gt);
	}
	qDeleteAll(m_gtasks);
}


void GanttMTask::replaceChildren() {
	TaskViewHelper tvh (m_task);
	if (!tvh.isExpanded()) {
		foreach(GanttTask* gt, m_gtasks) {
			gt->hide();
		}
		return;
	}
	QList<int> childrenPos = tvh.visualChildrenPos();
	for(int i=0; i<m_gtasks.size(); i++) {
		GanttTask* gt = m_gtasks.at(i);
		gt->show();
		gt->setPos(0, app()->rowHeight()*(1+childrenPos.at(i)));
		gt->replaceChildren();
	}
}


void GanttMTask::processExpansionChange() {
	TaskViewHelper tvh (m_task);
	if (tvh.isExpanded()) {
		foreach(GanttTask* gt, m_gtasks) {
			gt->show();
		}
	}
	else {
		foreach(GanttTask* gt, m_gtasks) {
			gt->hide();
		}
	}
}


GanttTask* GanttMTask::resolvTask(QString r_tbsId) {
	bool ok;
	int point = r_tbsId.indexOf('.');
	if (point == -1) {
		int pos = r_tbsId.toInt(&ok);
		if (!ok || pos < 0 || pos >= m_gtasks.size()) {
			return 0;
		}
		return m_gtasks.at(pos);
	}
	QString befPoint = r_tbsId.left(point);
	QString aftPoint = r_tbsId.right(r_tbsId.length() - (point+1));
	int pos = befPoint.toInt(&ok);
	if (!ok || pos < 0 || pos >= m_gtasks.size()) {
		return 0;
	}
	return m_gtasks.at(pos)->resolvTask(aftPoint);
}

GanttTask* GanttMTask::resolvAbsoluteTask(QString tbsId) {

	QString id = m_task->tbsId() + ".";
	if(!tbsId.startsWith(id)) {
		return 0;
	}
	tbsId = tbsId.right(tbsId.length() - id.length());

	if(tbsId.isEmpty()) {
		return this;
	}

	return resolvTask(tbsId);
}


void GanttMTask::resetTask(PC::Task *task) {
	removeAllTasks();
	GanttTask::resetTask(task);
	for (PC::Task::const_iterator ti=mTask()->taskBegin();
			ti!=mTask()->taskEnd();
			++ti) {
		GanttTask* gt = GanttScene::createGTask(app(), *ti, gCycle(), this);
		addTask(gt);
	}
	replaceChildren();
}

void GanttMTask::setCycleProp(PC::Cycle::Property p, const QVariant &value) {
	GanttTask::setCycleProp(p, value);
	foreach(GanttTask* gt, m_gtasks) {
		gt->setCycleProp(p, value);
	}
}

void GanttMTask::editModeChanged() {
	GanttTask::editModeChanged();
	foreach(GanttTask* gt, m_gtasks) {
		gt->editModeChanged();
	}
}
